package forwarder

import (
	"fmt"
	"net"
	"sync"
	"time"

	"nettools/shared/models"
	"nettools/shared/protocol"
	"nettools/shared/utils"
)

// InternalClient 内网客户端
type InternalClient struct {
	config     *models.ClientConfig
	serverConn net.Conn // 到服务器的连接

	// 会话管理
	sessions    map[string]*LocalSession // 本地会话
	sessionsMux sync.RWMutex

	// 重连控制
	connected       bool
	reconnectChan   chan struct{} // 重连信号通道
	reconnectTicker *time.Ticker

	// 控制通道
	stopChan chan struct{}
	wg       sync.WaitGroup
	running  bool
	mu       sync.RWMutex
}

// LocalSession 本地会话
type LocalSession struct {
	ID          string
	LocalConn   net.Conn // 到本地服务的连接
	ServiceName string
	TargetHost  string
	TargetPort  int
	CreatedAt   time.Time
}

// NewInternalClient 创建新的内网客户端
func NewInternalClient(config *models.ClientConfig) *InternalClient {
	return &InternalClient{
		config:        config,
		sessions:      make(map[string]*LocalSession),
		reconnectChan: make(chan struct{}, 1),
		stopChan:      make(chan struct{}),
	}
}

// Start 启动内网客户端
func (ic *InternalClient) Start() error {
	utils.Info("🚀 启动内网客户端...")
	utils.Info("客户端ID: %s", ic.config.ClientID)
	utils.Info("服务器地址: %s:%d", ic.config.ServerAddr, ic.config.ServerPort)

	ic.mu.Lock()
	ic.running = true
	ic.mu.Unlock()

	// 启动重连管理器
	ic.wg.Add(1)
	go ic.connectionManager()

	// 启动心跳协程
	ic.wg.Add(1)
	go ic.startHeartbeat()

	utils.Info("✅ 内网客户端启动成功!")
	return nil
}

// connectToServer 连接到服务器
func (ic *InternalClient) connectToServer() error {
	utils.Info("正在连接服务器...")

	serverAddr := fmt.Sprintf("%s:%d", ic.config.ServerAddr, ic.config.ServerPort)
	conn, err := net.DialTimeout("tcp", serverAddr, 10*time.Second)
	if err != nil {
		return fmt.Errorf("连接失败: %w", err)
	}

	ic.serverConn = conn
	utils.Info("✅ 已连接到服务器: %s", serverAddr)
	return nil
}

// registerServices 注册服务
func (ic *InternalClient) registerServices() error {
	utils.Info("正在注册服务...")

	// 构建服务信息
	var services []protocol.ServiceInfo
	for _, service := range ic.config.Services {
		svcInfo := protocol.ServiceInfo{
			Name:       service.Name,
			ServerPort: service.ServerPort,
			TargetHost: service.TargetHost,
			TargetPort: service.TargetPort,
			Protocol:   service.Protocol,
		}
		services = append(services, svcInfo)
		utils.Info("注册服务: %s (端口 %d -> %s:%d)",
			service.Name, service.ServerPort, service.TargetHost, service.TargetPort)
	}

	// 发送注册消息
	registerMsg := protocol.RegisterMessage{
		ClientID: ic.config.ClientID,
		Services: services,
	}

	if err := protocol.WriteMessage(ic.serverConn, protocol.MsgTypeRegister, registerMsg); err != nil {
		return fmt.Errorf("发送注册消息失败: %w", err)
	}

	// 等待注册响应
	msgType, data, err := protocol.ReadMessage(ic.serverConn)
	if err != nil {
		return fmt.Errorf("读取注册响应失败: %w", err)
	}

	if msgType != protocol.MsgTypeResponse {
		return fmt.Errorf("收到意外的消息类型: 0x%02x", msgType)
	}

	var response protocol.ResponseMessage
	if err := protocol.ParseMessage(msgType, data, &response); err != nil {
		return fmt.Errorf("解析注册响应失败: %w", err)
	}

	if !response.Success {
		return fmt.Errorf("注册失败: %s", response.Message)
	}

	utils.Info("✅ 服务注册成功: %s", response.Message)
	return nil
}

// connectionManager 连接管理器，负责连接和重连
func (ic *InternalClient) connectionManager() {
	defer ic.wg.Done()

	// 初始连接
	ic.triggerReconnect()

	// 创建重连定时器，每30秒检查一次连接状态
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ic.stopChan:
			utils.Info("连接管理器停止")
			return
		case <-ic.reconnectChan:
			ic.doReconnect()
		case <-ticker.C:
			// 定期检查连接状态
			if !ic.isConnected() {
				utils.Debug("检测到连接断开，触发重连")
				ic.triggerReconnect()
			}
		}
	}
}

// triggerReconnect 触发重连
func (ic *InternalClient) triggerReconnect() {
	select {
	case ic.reconnectChan <- struct{}{}:
	default:
		// 通道已满，重连已在进行中
	}
}

// doReconnect 执行重连
func (ic *InternalClient) doReconnect() {
	utils.Info("🔄 开始重连到服务器...")

	for attempt := 1; ; attempt++ {
		ic.mu.RLock()
		running := ic.running
		ic.mu.RUnlock()

		if !running {
			utils.Info("客户端已停止，终止重连")
			return
		}

		utils.Info("重连尝试 #%d...", attempt)

		// 关闭现有连接
		ic.closeConnection()

		// 尝试连接服务器
		if err := ic.connectToServer(); err != nil {
			utils.Error("连接服务器失败: %v", err)
			ic.waitBeforeRetry(attempt)
			continue
		}

		// 尝试注册服务
		if err := ic.registerServices(); err != nil {
			utils.Error("注册服务失败: %v", err)
			ic.closeConnection()
			ic.waitBeforeRetry(attempt)
			continue
		}

		// 连接成功
		ic.mu.Lock()
		ic.connected = true
		ic.mu.Unlock()

		utils.Info("✅ 重连成功! (尝试次数: %d)", attempt)

		// 启动消息处理
		ic.wg.Add(1)
		go ic.handleServerMessages()

		return
	}
}

// waitBeforeRetry 重连前等待
func (ic *InternalClient) waitBeforeRetry(attempt int) {
	// 计算退避延迟：min(30秒, 2^attempt 秒)
	delay := time.Duration(1<<uint(attempt)) * time.Second
	if delay > 30*time.Second {
		delay = 30 * time.Second
	}

	utils.Info("⏳ %d秒后重试...", int(delay.Seconds()))

	select {
	case <-time.After(delay):
	case <-ic.stopChan:
		return
	}
}

// closeConnection 关闭当前连接
func (ic *InternalClient) closeConnection() {
	ic.mu.Lock()
	ic.connected = false
	if ic.serverConn != nil {
		ic.serverConn.Close()
		ic.serverConn = nil
	}
	ic.mu.Unlock()

	// 清理所有会话
	ic.sessionsMux.Lock()
	for _, session := range ic.sessions {
		session.LocalConn.Close()
	}
	ic.sessions = make(map[string]*LocalSession)
	ic.sessionsMux.Unlock()
}

// isConnected 检查是否已连接
func (ic *InternalClient) isConnected() bool {
	ic.mu.RLock()
	defer ic.mu.RUnlock()
	return ic.connected && ic.serverConn != nil
}

// handleServerMessages 处理服务器消息
func (ic *InternalClient) handleServerMessages() {
	defer ic.wg.Done()
	utils.Info("开始处理服务器消息...")

	for {
		select {
		case <-ic.stopChan:
			return
		default:
			// 设置读取超时
			if ic.serverConn == nil {
				return
			}

			ic.serverConn.SetReadDeadline(time.Now().Add(30 * time.Second))

			msgType, data, err := protocol.ReadMessage(ic.serverConn)
			if err != nil {
				utils.Error("读取服务器消息失败: %v", err)
				ic.mu.Lock()
				ic.connected = false
				ic.mu.Unlock()

				// 触发重连
				ic.triggerReconnect()
				return
			}

			if err := ic.handleMessage(msgType, data); err != nil {
				utils.Error("处理服务器消息失败: %v", err)
			}
		}
	}
}

// handleMessage 处理消息
func (ic *InternalClient) handleMessage(msgType uint8, data []byte) error {
	switch msgType {
	case protocol.MsgTypeConnect:
		return ic.handleConnectRequest(data)
	case protocol.MsgTypeDisconnect:
		return ic.handleDisconnectRequest(data)
	case protocol.MsgTypeData:
		return ic.handleDataMessage(data)
	case protocol.MsgTypeHeartbeat:
		return ic.handleHeartbeat(data)
	default:
		utils.Debug("收到未知消息类型: 0x%02x", msgType)
		return nil
	}
}

// handleConnectRequest 处理连接请求
func (ic *InternalClient) handleConnectRequest(data []byte) error {
	var connectMsg protocol.ConnectMessage
	if err := protocol.ParseMessage(protocol.MsgTypeConnect, data, &connectMsg); err != nil {
		return fmt.Errorf("解析连接消息失败: %w", err)
	}

	utils.Info("收到连接请求: 会话=%s, 目标=%s:%d",
		connectMsg.SessionID, connectMsg.TargetHost, connectMsg.TargetPort)

	// 连接到本地目标服务
	targetAddr := fmt.Sprintf("%s:%d", connectMsg.TargetHost, connectMsg.TargetPort)
	localConn, err := net.DialTimeout("tcp", targetAddr, 5*time.Second)
	if err != nil {
		utils.Error("连接本地服务失败: %v", err)
		// 发送错误响应
		errorMsg := protocol.ErrorMessage{
			Code:    500,
			Message: fmt.Sprintf("连接本地服务失败: %v", err),
		}
		return protocol.WriteMessage(ic.serverConn, protocol.MsgTypeError, errorMsg)
	}

	utils.Info("✅ 已连接到本地服务: %s", targetAddr)

	// 创建本地会话
	session := &LocalSession{
		ID:          connectMsg.SessionID,
		LocalConn:   localConn,
		ServiceName: connectMsg.ServiceName,
		TargetHost:  connectMsg.TargetHost,
		TargetPort:  connectMsg.TargetPort,
		CreatedAt:   time.Now(),
	}

	ic.sessionsMux.Lock()
	ic.sessions[connectMsg.SessionID] = session
	ic.sessionsMux.Unlock()

	// 启动数据转发协程
	ic.wg.Add(1)
	go ic.forwardLocalData(session)

	return nil
}

// handleDisconnectRequest 处理断开连接请求
func (ic *InternalClient) handleDisconnectRequest(data []byte) error {
	var disconnectMsg protocol.ConnectMessage
	if err := protocol.ParseMessage(protocol.MsgTypeDisconnect, data, &disconnectMsg); err != nil {
		return fmt.Errorf("解析断开连接消息失败: %w", err)
	}

	utils.Info("收到断开连接请求: 会话=%s", disconnectMsg.SessionID)

	// 查找并关闭会话
	ic.sessionsMux.Lock()
	session, exists := ic.sessions[disconnectMsg.SessionID]
	if exists {
		delete(ic.sessions, disconnectMsg.SessionID)
	}
	ic.sessionsMux.Unlock()

	if exists && session.LocalConn != nil {
		session.LocalConn.Close()
		utils.Info("✅ 会话已关闭: %s", disconnectMsg.SessionID)
	}

	return nil
}

// handleDataMessage 处理数据消息
func (ic *InternalClient) handleDataMessage(data []byte) error {
	var dataMsg protocol.DataMessage
	if err := protocol.ParseMessage(protocol.MsgTypeData, data, &dataMsg); err != nil {
		return fmt.Errorf("解析数据消息失败: %w", err)
	}

	// 查找对应的会话
	ic.sessionsMux.RLock()
	session, exists := ic.sessions[dataMsg.SessionID]
	ic.sessionsMux.RUnlock()

	if !exists {
		return fmt.Errorf("会话不存在: %s", dataMsg.SessionID)
	}

	// 转发数据到本地服务
	_, err := session.LocalConn.Write(dataMsg.Data)
	if err != nil {
		utils.Error("转发数据到本地服务失败: %v", err)
		// 清理会话
		ic.sessionsMux.Lock()
		delete(ic.sessions, dataMsg.SessionID)
		ic.sessionsMux.Unlock()
		session.LocalConn.Close()
	}

	return err
}

// handleHeartbeat 处理心跳
func (ic *InternalClient) handleHeartbeat(data []byte) error {
	// 简单回复心跳
	heartbeat := protocol.HeartbeatMessage{
		Timestamp: time.Now().Unix(),
	}
	return protocol.WriteMessage(ic.serverConn, protocol.MsgTypeHeartbeat, heartbeat)
}

// forwardLocalData 转发本地数据
func (ic *InternalClient) forwardLocalData(session *LocalSession) {
	defer ic.wg.Done()
	defer func() {
		// 清理会话
		ic.sessionsMux.Lock()
		delete(ic.sessions, session.ID)
		ic.sessionsMux.Unlock()
		session.LocalConn.Close()
	}()

	utils.Debug("开始转发本地数据: 会话=%s", session.ID)

	buffer := make([]byte, 32*1024) // 32KB 缓冲区
	for {
		n, err := session.LocalConn.Read(buffer)
		if err != nil {
			utils.Debug("本地连接读取结束: %v", err)
			return
		}

		// 转发数据到服务器
		dataMsg := protocol.DataMessage{
			SessionID: session.ID,
			Data:      buffer[:n],
		}

		if err := protocol.WriteMessage(ic.serverConn, protocol.MsgTypeData, dataMsg); err != nil {
			utils.Error("转发数据到服务器失败: %v", err)
			return
		}
	}
}

// startHeartbeat 启动心跳
func (ic *InternalClient) startHeartbeat() {
	defer ic.wg.Done()

	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ic.stopChan:
			return
		case <-ticker.C:
			// 检查是否已连接
			if !ic.isConnected() {
				continue
			}

			heartbeat := protocol.HeartbeatMessage{
				Timestamp: time.Now().Unix(),
			}

			if err := protocol.WriteMessage(ic.serverConn, protocol.MsgTypeHeartbeat, heartbeat); err != nil {
				utils.Error("发送心跳失败: %v", err)
				ic.mu.Lock()
				ic.connected = false
				ic.mu.Unlock()

				// 触发重连
				ic.triggerReconnect()
				return
			}
			utils.Debug("❤️ 心跳发送成功")
		}
	}
}

// GetSessionCount 获取会话数量
func (ic *InternalClient) GetSessionCount() int {
	ic.sessionsMux.RLock()
	defer ic.sessionsMux.RUnlock()
	return len(ic.sessions)
}

// IsConnected 检查是否已连接（公开方法）
func (ic *InternalClient) IsConnected() bool {
	return ic.isConnected()
}

// Stop 停止内网客户端
func (ic *InternalClient) Stop() error {
	utils.Info("🛑 正在停止内网客户端...")

	ic.mu.Lock()
	ic.running = false
	ic.mu.Unlock()

	// 发送停止信号
	close(ic.stopChan)

	// 关闭服务器连接
	if ic.serverConn != nil {
		ic.serverConn.Close()
	}

	// 关闭所有本地会话
	ic.sessionsMux.Lock()
	for _, session := range ic.sessions {
		session.LocalConn.Close()
	}
	ic.sessionsMux.Unlock()

	// 等待所有协程结束
	ic.wg.Wait()

	utils.Info("✅ 内网客户端已停止")
	return nil
}
